﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Web.Mvc;
using DotNet.Highcharts;
using DotNet.Highcharts.Enums;
using DotNet.Highcharts.Helpers;
using DotNet.Highcharts.Options;
using Mondial2014.Models.Competition;
using Mondial2014.Models.Context;
using Mondial2014.Utils;
using Mondial2014.Utils.Extensions;

namespace Mondial2014.Controllers
{
    public class StatsController : Controller
    {
        #region context
        private readonly Mondial2014DbContext m_Context = new Mondial2014DbContext();
        #endregion

        #region Index

        // GET: Stats
        public ActionResult Index()
        {
            return View();
        }

        #endregion

        #region QualifiersStats

        public class QualifiersStatsViewModel
        {
            public int Part { get; set; }
            public Highcharts WinnersHighcharts { get; set; }
            public Highcharts FinalsHighcharts { get; set; }
            public Highcharts SemisHighcharts { get; set; }
            public Highcharts QuarterssHighcharts { get; set; }
            public Highcharts Last16SHighcharts1 { get; set; }
            public Highcharts Last16SHighcharts2 { get; set; }
        }

        public ActionResult QualifiersStats(int? part)
        {
            var model = new QualifiersStatsViewModel
            {
                Part = (part.HasValue) ? part.Value : 0,
                WinnersHighcharts =
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Winner), "winners", "מי תזכה"),
                FinalsHighcharts = 
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Final), "Finals", "מי תעלה לגמר"),
                SemisHighcharts =
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Semi), "semis", "מי תעלה לחצי"),
                QuarterssHighcharts =
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Quarter), "quarters", "מי תעלה לרבע"),
                Last16SHighcharts1 =
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Last16), "last16s0", "מי תעלה לשמינית", 0, 15),
                Last16SHighcharts2 =
                    CreateWinnersHighcharts(GetQualifiersForStage(StageType.Last16), "last16s1", "מי תעלה לשמינית", 1, 15),
            };

            return View(model);
        }

        public IQueryable<IGrouping<string, string>> GetQualifiersForStage(StageType stageType)
        {
            return m_Context.KnockoutGambles
                .Where(g => g.Stage.Level == (int)stageType && g.Team != null)
                .Select(g => g.Team.Name)
                .GroupBy(name => name);
        }

        public Highcharts CreateWinnersHighcharts(IQueryable<IGrouping<string,string>> stats, string chartName, string chartDisplayName, int partition = 0, int partitionSize = 20)
        {
            stats = stats.OrderBy(g => g.Count());
            var groupNames = stats.Select(g => g.Key)
                                    .Select(name => name.Replace("'", ""))
                                    .Skip(partition * partitionSize)
                                    .Take(partitionSize).ToArray();
            var groupCounts = stats.Select(g => g.Count()).Skip(partition * partitionSize).Take(partitionSize).ToArray();

            return new Highcharts(chartName)
                .InitChart(new Chart { DefaultSeriesType = ChartTypes.Column})
                .SetTitle(new Title { Text = chartDisplayName })
                .SetXAxis(new XAxis { Categories = groupNames })
                .SetYAxis(new YAxis { Title = new YAxisTitle { Text = "מספר משתתפים" }, AllowDecimals = false })
                .SetPlotOptions(new PlotOptions
                {
                    Line = new PlotOptionsLine
                    {
                        DataLabels = new PlotOptionsLineDataLabels
                        {
                            Enabled = true
                        },
                        EnableMouseTracking = true
                    }
                })
                .SetSeries(new[]
                {
                    new Series { Name = "קבוצות", Data = new Data( groupCounts.Cast<object>().ToArray() )}
                });
        }

        #endregion

        #region GammesResultsStats

        public class GameResultStatsViewModel
        {
            public int GameNumber       { get; set; }
            public string Date          { get; set; }
            public string Team1Name     { get; set; }
            public string Team2Name     { get; set; }
            public FixtureResult Result { get; set; }
            public int Guessed1         { get; set; }
            public int Guessed2         { get; set; }
            public int GuessedX         { get; set; }
            public string Percent1      { get; set; }
            public string Percent2      { get; set; }
            public string PercentX      { get; set; }
        }

        public ActionResult GammesResultsStats()
        {
            var models = new List<GameResultStatsViewModel>();
            foreach (var fixtureIterator in m_Context.GetFixtures().OrderBy(f => f.Number).ToArray())
            {
                var fixture = fixtureIterator;

                var fixtureGambles = m_Context.GameGambles.Where(gg => gg.Fixture.Number == fixture.Number);
                var totalGambles = fixtureGambles.Count();
                var team1Gambles = fixtureGambles.Count(g => g.FixtureResult == FixtureResult.Team1);
                var team2Gambles = fixtureGambles.Count(g => g.FixtureResult == FixtureResult.Team2);
                var xGambles = fixtureGambles.Count(g => g.FixtureResult == FixtureResult.Tie);

                var model = new GameResultStatsViewModel
                {
                    GameNumber = fixture.Number,
                    Date = fixture.Date.ToString("d.MM"),
                    Team1Name = fixture.Team1.Name,
                    Team2Name = fixture.Team2.Name,
                    Result = fixture.GetGameResult(),
                    Guessed1 = team1Gambles,
                    Guessed2 = team2Gambles,
                    GuessedX = xGambles,
                    Percent1 = GetPercentDisplay(team1Gambles, totalGambles),
                    Percent2 = GetPercentDisplay(team2Gambles, totalGambles),
                    PercentX = GetPercentDisplay(xGambles, totalGambles)
                };

                models.Add(model);
            }

            return View(models);
        }

        private static string GetPercentDisplay(int count, int total)
        {
            return string.Format("{0}", (count*100)/total);
        }

        #endregion

        #region ScoreProgressStats

        public ActionResult ScoreProgressStats()
        {
            var firstDay = m_Context.Fixtures.Where(f => f.Played).OrderBy(f => f.Date).Select(f => f.Date).First();
            var lastDay = m_Context.Fixtures.Where(f => f.Played).OrderByDescending(f => f.Date).Select(f => f.Date).First().AddDays(2);
            var days = Enumerable.Range(0, (lastDay - firstDay).Days).ToArray();

            var allSeries = new Collection<Series>();

            foreach (var player in m_Context.Gamblers.ToArray())
            {
                var seriesData = new Collection<object>();

                foreach (var day in days)
                {
                    var dayScore = GamblerScoreCalculator.CalculateScoreForPlayerUntilDate(player.Id, firstDay.AddDays(day - 1));
                    seriesData.Add(dayScore);
                }

                allSeries.Add(new Series{ Name = player.Name, Data = new Data(seriesData.ToArray()) });
            }

            var chart = new Highcharts("ScoreProgress")
                .InitChart(new Chart { DefaultSeriesType = ChartTypes.Line })
                .SetTitle(new Title { Text = "שינוי ניקוד לפי ימים" })
                .SetXAxis(new XAxis { Categories = days.Select(d => d.ToString()).ToArray() })
                .SetYAxis(new YAxis { Title = new YAxisTitle { Text = "משתתפים" }, Min = 0 })
                .SetPlotOptions(new PlotOptions
                {
                    Line = new PlotOptionsLine
                    {
                        DataLabels = new PlotOptionsLineDataLabels
                        {
                            Enabled = true
                        },
                        EnableMouseTracking = true
                    }
                })
                // load the Y values
                .SetSeries(allSeries.ToArray());

            return View(chart);
        }

        #endregion

        #region HaifaVsPtk

        public class CitiesCompetitionViewModel
        {
            public CitiesCompetitionViewModel()
            {
                CityToNames = new Dictionary<string, IEnumerable<string>>();
                CityDistribution = new Collection<Highcharts>();
            }
            public IDictionary<string, IEnumerable<string>> CityToNames;
            public Highcharts CitiesChart { get; set; }
            public Collection<Highcharts> CityDistribution { get; set; }
        }

        public ActionResult HaifaVsPtk()
        {
            var model = new CitiesCompetitionViewModel();
            
            var gamblerGroups = m_Context.Gamblers.GroupBy(g => g.Address.City).ToArray();

            model.CityToNames = gamblerGroups.ToDictionary(
                group => group.Key.Name,
                group => group.Select(g => g.Name));

            var maxPerGroup = gamblerGroups.Max(g => g.Count());
            var groupsScores = new Collection<object>();
            var groupsNormaledScore = new Collection<object>();
            foreach (var gamblerGroup in gamblerGroups)
            {
                var groupScore = gamblerGroup.Sum(g => g.TotalScore);
                var normaledScore = groupScore * ((double)maxPerGroup / gamblerGroup.Count());

                groupsScores.Add(groupScore);
                groupsNormaledScore.Add(normaledScore);
            }
            model.CitiesChart = GetCitiesHighcharts(gamblerGroups.Select(g => g.Key.Name).ToArray(), groupsScores.ToArray(), groupsNormaledScore.ToArray());

            var chartId = 0;
            foreach (var gamblerGroup in gamblerGroups)
            {
                model.CityDistribution.Add(GetCityDistribution(
                    chartId++,
                    gamblerGroup.Key.Name,
                    gamblerGroup.Select(g => g.Name).ToArray(),
                    gamblerGroup.Select(g => g.TotalScore).Cast<object>().ToArray()));
            }

            return View(model);
        }

        private Highcharts GetCityDistribution(int id, string city, string[] gamblerNames, object[] scores)
        {
            return new Highcharts("CityDistribution" + id)
                .InitChart(new Chart { DefaultSeriesType = ChartTypes.Pie })
                .SetTitle(new Title { Text = "התפלגות נקודות " + city })
                .SetXAxis(new XAxis { Categories = gamblerNames })
                .SetYAxis(new YAxis { Title = new YAxisTitle { Text = "משתתפים" }, AllowDecimals = false })
                .SetPlotOptions(new PlotOptions
                {
                    Line = new PlotOptionsLine
                    {
                        DataLabels = new PlotOptionsLineDataLabels
                        {
                            Enabled = true
                        },
                        EnableMouseTracking = true
                    }
                })
                .SetSeries(new[]
                {
                    new Series { Name = "נקודות למשתתף", Data = new Data( scores )},
                });
        }

        private Highcharts GetCitiesHighcharts(string[] cities, object[] scores, object[] citiesNormaledScores)
        {
            return new Highcharts("HaifaVsPtk")
                .InitChart(new Chart { DefaultSeriesType = ChartTypes.Column })
                .SetTitle(new Title { Text = "חיפה נגד פתח תקווה!!" })
                .SetXAxis(new XAxis { Categories = cities })
                .SetYAxis(new YAxis { Title = new YAxisTitle { Text = "נקודות לקבוצה" }, AllowDecimals = true })
                .SetPlotOptions(new PlotOptions
                {
                    Line = new PlotOptionsLine
                    {
                        DataLabels = new PlotOptionsLineDataLabels
                        {
                            Enabled = true
                        },
                        EnableMouseTracking = true
                    }
                })
                .SetSeries(new[]
                {
                    new Series { Name = "נקודות לקבוצה", Data = new Data( scores )},
                    new Series { Name = "נקודות מנורמלות לקבוצה", Data = new Data( citiesNormaledScores )}
                });
        }

        #endregion

        #region Chart example

        private Highcharts GetCharHighcharts(int index)
        {
            return new Highcharts("chart" + index)
                //define the type of chart
                .InitChart(new Chart { DefaultSeriesType = ChartTypes.Line })
                //overall title of the chart
                .SetTitle(new Title { Text = "Gambling Stats" })
                //small label below the main Title
                .SetSubtitle(new Subtitle { Text = "stats team" })
                //load the x values
                .SetXAxis(new XAxis { Categories = new[] { "Brazil", "Croatia", "Holand" } })
                //set the Y title
                .SetYAxis(new YAxis { Title = new YAxisTitle { Text = "Number of Wins" } })
                .SetTooltip(new Tooltip
                {
                    Enabled = true,
                    Formatter = @"function() { return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y }"
                })
                .SetPlotOptions(new PlotOptions
                {
                    Line = new PlotOptionsLine
                    {
                        DataLabels = new PlotOptionsLineDataLabels
                        {
                            Enabled = true
                        },
                        EnableMouseTracking = true
                    }
                })
                // load the Y values
                .SetSeries(new[]
                {
                    new Series { Name = "Wins", Data = new Data(new object[] { 1, 2, 3 })}
                });
        }

        #endregion
    }
}